package hehe.validation.annotation;


import hehe.validation.base.Rule;
import hehe.validation.base.Verify;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 验证器注解处理器积基类
 *<B>说明：</B>
 *<pre>
 * 略
 *</pre>
 *<B>示例：</B>
 *<pre>
 *  略
 *</pre>
 *<B>日志：</B>
 *<pre>
 *  略
 *</pre>
 *<B>注意事项：</B>
 *<pre>
 *  略
 *</pre>
 */
public class BaseValidatorProcessor
{
    protected Annotation annotation;
    protected Class targetClazz;
    protected Field field;
    protected Rule rule;
    protected Verify verify;
    protected String name;

    public void configure(Annotation annotation,Class targetClazz, Field field,String name)
    {
        this.annotation = annotation;
        this.field = field;
        this.targetClazz = targetClazz;

        if (name == null|| name.equals("")) {
            this.name = this.getAnnotationAttr(Rule.NAME_VALIDATOR_ANNOTATION);
        } else {
            this.name = name;
        }

        this.init();
        this.setValidatorParam();
    }

    /**
     * 初始化对象
     *<B>说明：</B>
     *<pre>
     *  创建规则对象,创建验证信息
     *</pre>
     */
    private void init()
    {

        Rule rule = ValidAnnotation.getLastRule(this.targetClazz,this.field);

        if (rule == null) {
            rule = new Rule(this.field.getName());
            ValidAnnotation.addRule(this.targetClazz,this.field,rule);
        }

        this.rule = rule;
        this.verify = new Verify(this.name);

        this.rule.add(this.verify);
    }

    /**
     * 设置通用验证参数
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    protected void setValidatorParam()
    {

        String[] scene = this.getAnnotationAttr(Rule.SCENE_VALIDATOR_ANNOTATION);
        if (scene.length > 0) {
            this.rule.scene(scene);
        }

        // 当当前规则验证未通过时,是否继续往下验证其他规则
        boolean goOn = this.getAnnotationAttr(Rule.GOON_VALIDATOR_ANNOTATION);
        if (goOn == true) {
            this.rule.goOn();
        }

        this.rule.add(verify);
        ValidAnnotation.addRule(this.targetClazz,this.field,rule);
    }

    /**
     * 设置verify属性
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    protected void put(String name,Object value)
    {
        this.verify.put(name,value);
    }

    protected void puts(String... names)
    {
        Map<String,Object> attrs = this.getAnnotationAttrs(names);
        this.verify.putAll(attrs);
    }

    protected void putVerify()
    {
        Map<String,Object> attrs = this.getAnnotationAttrs();
        this.verify.putAll(attrs);
    }

    /**
     * 获取当期规则
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    protected Rule getRule()
    {
        return this.rule;
    }

    /**
     * 获取注解所有属性
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public Map<String,Object> getAnnotationAttrs()
    {
        Map<String,Object> attrs = new HashMap<>();
        Method[] methods = this.annotation.annotationType().getDeclaredMethods();
        for (Method method:methods) {
            try {
                attrs.put(method.getName(),method.invoke(this.annotation));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        return attrs;
    }

    /**
     * 获取所有属性
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    protected Map<String,Object> getAnnotationAttrs(String... names)
    {
        Map<String,Object> attrs = new HashMap<>();

        for (String name:names) {
            try {
                Method method = this.annotation.annotationType().getDeclaredMethod(name, (Class<?>[]) null);
                attrs.put(method.getName(),method.invoke(this.annotation,(Object[]) null));
            } catch (Exception ex) {
                // 不作任何处理
            }
        }

        return attrs;
    }

    /**
     * 获取注解属性值
     *<B>说明：</B>
     *<pre>
     *  通过反射调用注解方法,获取数据
     *</pre>
     */
    protected <T> T getAnnotationAttr(String attrName)
    {
        try {
            Method method = this.annotation.annotationType().getDeclaredMethod(attrName, (Class<?>[]) null);
            return (T)method.invoke(this.annotation,(Object[]) null);
        } catch (Exception ex) {
            return null;
        }
    }

}
